﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace WcfMasterSlaveElectionService
{
    /// <summary>
    /// Watchdog that keeps checking if the master is valid
    /// </summary>
    internal class Watchdog
    {
        /// <summary>
        /// While false, keeps the master watchdog thread alive. If set to true, the wactchdog thread will end.
        /// </summary>
        private ManualResetEvent _masterWatchEvent;
        /// <summary>
        /// Watchdog thread: keep checking if the master is valid
        /// </summary>
        private Thread _masterWatchdogThread;
        /// <summary>
        /// Interface for logging
        /// </summary>
        private ILog _logger;
        /// <summary>
        /// Reference to the master election service
        /// </summary>
        private MasterElectionService _service;

        public Watchdog(MasterElectionService service, ILog logger)
        {
            _masterWatchEvent = new ManualResetEvent(false);
            _service = service;
            _logger = logger;
        }

        /// <summary>
        /// Starts the watchdog
        /// </summary>
        internal void Start()
        {
            _masterWatchEvent.Reset();
            //start the master watchdog thread to keep checking if the master is running
            // Slave and master both execute the watchdog thread.
            startMasterWatchdogThread();
        }

        /// <summary>
        /// Stops the watchdog
        /// </summary>
        internal void Stop()
        {
            _masterWatchEvent.Set();
        }

        /// <summary>
        /// Gets if the watchdog thread is running
        /// </summary>
        /// <returns></returns>
        internal bool IsWatchdogAlive()
        {
            bool isAlive = false;
            if (_masterWatchdogThread != null)
            {
                isAlive = _masterWatchdogThread.IsAlive;
            }
            return isAlive;
        }

        /// <summary>
        /// This thread keeps checking if the master is running for every 2 minutes and if it is down
        /// will implement the failover logic to elect one of the slaves as master and make other slaves 
        /// replicate from new master
        /// </summary>
        private void startMasterWatchdogThread()
        {
            _logger.LogMessage("Starting Master Watchdog thread");

            _masterWatchdogThread = new Thread(delegate()
            {
                while (!_masterWatchEvent.WaitOne(TimeSpan.FromSeconds(30)))
                {
                    _logger.LogMessage("Watchdog: validate master");
                    if (_service.IsMaster())
                    {
                        _service.ExpectMaster(true); // let the process know that we expect it to behave as master
                        _logger.LogMessage("Watchdog: we are master, no checking needed");
                        continue;
                    }

                    _service.ExpectMaster(false); // let the process know that we expect it to behave as slave

                    //if validate master fails implement failover logic
                    if (!_service.ValidateMaster())
                    {
                        _logger.LogMessage("Watchdog: Master is not valid. Start election!");
                        _service.EnsureMasterElected();
                    }
                    else
                    {
                        _logger.LogMessage("Watchdog: Master is valid");
                    }
                }

                _logger.LogMessage("Watchdog thread is stopped");
            });

            _masterWatchdogThread.Start();
        }
    }
}
